using System;

namespace micsun.Logic.Security
{
	public sealed class Permission
	{
		internal Permission(DateTime timeStamp,object data)
		{
			_timeStamp = timeStamp;
			_permissionData = data;
		}

		private DateTime _timeStamp;
		internal DateTime TimeStamp
		{
			get {
				return _timeStamp;
			}
		}

		private object _permissionData;
		public object Data
		{
			get {
				return _permissionData;
			}
		}

		public bool Check(object permission)
		{
			if(permission==null)
				return false;
			if(permission is string && (string)permission=="_SYSTEM_")
				return true;
			return PermissionStock.Instance.CheckPermission(this,permission);
		}

		public static void InitializePermissionStock(object[] allPermissions) {
			PermissionStock.Instance.InitializePermissionStock(allPermissions);
		}

		public static Permission CreatePermission(object[] allowedPermissions) {
			return PermissionStock.Instance.CreatePermission(allowedPermissions);
		}
	}
	/// <summary>
	/// 
	/// </summary>
	internal sealed class PermissionStock
	{
		public static void Reload()
		{
			_instance = new PermissionStock();
		}
		private static PermissionStock _instance;
		public static PermissionStock Instance
		{
			get {
				if (_instance==null) Reload();
				return _instance;
			}
		}

		private PermissionStock()
		{
			_timeStamp=DateTime.Now;
		}

		private int _count;
		private CaseInsensitiveCollection _position;

		private readonly DateTime _timeStamp;

		public void InitializePermissionStock(object[] allPermissions) {
			if( allPermissions==null||_position!=null )
				return;
			_position = new CaseInsensitiveCollection(allPermissions.Length);
			
			lock(this) {
				for( int i=0;i<allPermissions.Length;i++ ) {
					_position.Add( allPermissions[i],i );
				}
				_count = allPermissions.Length;
			}
		}

		public Permission CreatePermission( object[] allowedPermissions )
		{
			bool[] permissonData = new bool[_count];
			for(int i=0;i<permissonData.Length;i++)
				permissonData[i]=false;
			if(allowedPermissions!=null) {
				for(int i=0;i<allowedPermissions.Length;i++ ) {
					if( _position.Contains(allowedPermissions[i]) ) {
						int pos = (int)_position[allowedPermissions[i]];
						permissonData[pos]=true;
					}
				}
			}
			return new Permission(_timeStamp,permissonData);
		}

		public bool CheckPermission(Permission p,object check)
		{
			if( p.TimeStamp!=this._timeStamp )
				throw new ApplicationException("The permission object is out of expiry time,please reload again.");
			bool[] permissionData = (bool[])p.Data;
			if( _position[check] !=null )
			{
				int pos = (int)_position[check];
				return permissionData[pos];
			}
			else
				return false;
		}
	}
}
